﻿using System;
using System.Data.Services.Client;
using System.Linq;
using System.Windows;
using Microsoft.Phone.Shell;
using Tfs.OnTheRoad.Model;
using System.Collections.Generic;
using Tfs.OnTheRoad.Controls.ChartStrategies;
using System.Net;
namespace Tfs.OnTheRoad.ViewModel
{
    /// <summary>
    /// Work Items Chart ViewModel
    /// </summary>
    public class WorkItemsChartViewModel : BaseViewModel
    {
        public List<string> ChartFields { get; private set; }
        public List<BaseChartStrategy> ChartStrategies { get; private set; }
        public string ChartSettingsName { get; set; }
        public WorkItemsChartViewModel(string settingsName) : this(settingsName, 1, null, null) { }
        private string _queryPattern = string.Empty;
        private string _summaryEntity = string.Empty;
        private string _currentFilter = string.Empty;
        private int _currentLevel = 1;
        public WorkItemsChartViewModel(string settingsName, int level, Query currentQuery, string filter)
            : base()
        {
            _currentLevel = level;
            _currentFilter = filter;
            //Settings stored per level
            ChartSettingsName = string.Format("{0}_{1}", settingsName, level);
            ChartFields = new List<string>() { "AreaPath", "AssignedTo", "ChangedDate", "CreatedDate", "CreatedBy", "IterationPath", "Priority", "Reason", "ResolvedBy", "State", "Type" };
            CurrentChartStrategy = Helpers.SettingsStorageHelper.ReadChartSettings(ChartSettingsName);
            if (CurrentChartStrategy == null)
                CurrentChartStrategy = new Tfs.OnTheRoad.Controls.ChartStrategies.StackedColumnChartStrategy() { Field1 = "State", Field2 = "Type" };            


            ChartStrategies = new List<BaseChartStrategy>();
            //Loading all available chart strategies
            var loadedStrategies = from type in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
                                   where !type.IsAbstract && type.IsSubclassOf(typeof(BaseChartStrategy)) &&
                                         string.Compare(CurrentChartStrategy.GetType().FullName,type.FullName)!=0
                                   orderby type.Name
                                   select (BaseChartStrategy)System.Activator.CreateInstance(type);
            ChartStrategies.AddRange(loadedStrategies);
            //The we add the current one
            ChartStrategies.Add(CurrentChartStrategy);
            
                        
            CurrentQuery = currentQuery;


            
            System.Text.StringBuilder additionalQueryParameters = new System.Text.StringBuilder();
            var currentProject = PhoneApplicationService.Current.State["CurrentProject"] as Project;
            if (currentQuery != null)
            {
                _queryPattern = string.Format("Queries('{0}')/WorkItems?$select={1}", CurrentQuery.Id, "{0}"/*Later we change*/);
            }
            else
            {
                if (!string.IsNullOrEmpty(filter))
                {                    
                    //Coming from drill down of the project overview. Only one type!(Types[0])
                    _queryPattern = string.Format("Projects('{0}')/WorkItems?$select={1}", currentProject.Name, "{0}"/*Later we change*/);
                }
                else
                    _queryPattern = string.Format("Projects('{0}')/WorkItems?$select={1}", currentProject.Name, "{0}"/*Later we change*/);     
            }
            if (!string.IsNullOrEmpty(filter))
                _queryPattern += string.Format("&$filter={0}", HttpUtility.UrlEncode(filter));
            setupChartStrategy();
        }

        private void setupChartStrategy()
        {
            _workItemsSummary = new WorkItemsSummaryList();
            _summaryEntity = string.Format(_queryPattern, CurrentChartStrategy.SelectFields);            
        }
        private bool _processing;

        public bool Processing
        {
            get { return _processing; }
            set
            {
                _processing = value;
                this.RaisePropertyChanged("Processing");
            }
        }

        bool summaryLoaded = false;
        public void CalculateSummary()
        {
            if (!summaryLoaded)
            {
                DataServiceCollection<WorkItem> workItemsSummary;
                var context = App.CreateTfsDataServiceContext();
                workItemsSummary = new DataServiceCollection<WorkItem>(context);
                workItemsSummary.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(summary_LoadCompleted);
                workItemsSummary.LoadAsync(new Uri(_summaryEntity, UriKind.Relative));
                Processing = true;
                summaryLoaded = true;                
            }
        }

        public event EventHandler ChartDataPrepared;

        void summary_LoadCompleted(object sender, LoadCompletedEventArgs e)
        {
            DataServiceCollection<WorkItem> workItemsSummary = sender as DataServiceCollection<WorkItem>;
            if (!e.Cancelled && workItemsSummary != null)
            {
                ProcessData(workItemsSummary);               
                if (ChartDataPrepared != null)
                    ChartDataPrepared(this, EventArgs.Empty);
            }
            else 
            {
                if(e.Error != null)
                    MessageBox.Show(e.Error.Message);
            }
            Processing = false;
        }

        private int _workItemsCount;

        public int WorkItemsCount
        {
            get { return _workItemsCount; }
            set
            {
                _workItemsCount = value;
                this.RaisePropertyChanged("WorkItemsCount");
            }
        }

        private WorkItemsSummaryList _workItemsSummary;
        public WorkItemsSummaryList WorkItemsSummary
        {
            get { return _workItemsSummary; }
        }

        private Query _currentQuery;

        public Query CurrentQuery
        {
            get { return _currentQuery; }
            set { _currentQuery = value; }
        }

        BaseChartStrategy _currentChartStrategy;
        public BaseChartStrategy CurrentChartStrategy
        {
            get
            {
                return _currentChartStrategy;
            }
            set
            {
                _currentChartStrategy = value;
                if (value != null)
                {
                    setupChartStrategy();
                    summaryLoaded = false;
                }
            }
        }

        public void ProcessData(DataServiceCollection<WorkItem> workItems)
        {
            _workItemsSummary.Clear();
            
            //getting all workItem types(will be used by the WorkItemsOverviewPage page)
            var wiTypesQuery = (from wi in workItems
                                select wi.Type).Distinct();
            PhoneApplicationService.Current.State["WorkItemsTypes"] = wiTypesQuery.ToArray();

            //Reflection Properties which will be used to display the Data
            System.Reflection.PropertyInfo field1Property = typeof(WorkItem).GetProperty(CurrentChartStrategy.Field1);

            //Function with formats the values that are comming(specially dates)
            Func<object, object> getAndConvertValue = delegate(object rawValue)
            {
                if (rawValue is DateTime)
                    return ((DateTime)rawValue).Date;
                else if (rawValue == null)
                    return string.Empty;
                else
                    return rawValue;
            };


            //Getting state groups
            WorkItemsCount = workItems.Count;

            var wiTypesSummaryByField1 = from wi in workItems
                                         group wi by getAndConvertValue(field1Property.GetValue(wi, null)) into Field1Group
                                         orderby Field1Group.Count() descending
                                         select new { Field1 = Field1Group.Key,
                                                      Count = Field1Group.Count()
                                         };

            System.Reflection.PropertyInfo field2Property = null;
            if (CurrentChartStrategy.IsStacked)
                field2Property = typeof(WorkItem).GetProperty(CurrentChartStrategy.Field2);

            foreach (var field1Group in wiTypesSummaryByField1)
            {
                var itemField1 = new WorkItemSummaryItem() { GroupLevel1 = field1Group.Field1, Count = field1Group.Count, FieldName = CurrentChartStrategy.Field1, PreviousLevelFilter = _currentFilter, CurrentLevel=_currentLevel };
                _workItemsSummary.Add(itemField1);
                if (CurrentChartStrategy.IsStacked)
                {
                    //Now let's build a query to group the WI Type by State
                    var wiTypeSummaryByField2 = from wi in workItems
                                                where field1Property.GetValue(wi, null).Equals(field1Group.Field1)
                                                //string.Compare(wi.State, stateItem.State, StringComparison.OrdinalIgnoreCase) == 0
                                                group wi by getAndConvertValue(field2Property.GetValue(wi, null)) into Field2Group
                                                orderby Field2Group.Count() descending
                                                where Field2Group.Count() > 0                                                
                                                select new { Field2 = Field2Group.Key, Count = Field2Group.Count() };
                    foreach (var field2Group in wiTypeSummaryByField2)
                        itemField1.Items.Add(new WorkItemSummaryItem.ChildSummaryItem() { Parent = itemField1, ChildLevel = field2Group.Field2, Count = field2Group.Count, FieldName = CurrentChartStrategy.Field2 });
                }
            }

            //Let's take the last XX characters of every caption
            int sizeToTruncate = 35;
            foreach (var item in _workItemsSummary)
            {
                if (item.Caption.Length > sizeToTruncate)
                    item.Caption = string.Format("...{0}", item.Caption.Substring(item.Caption.Length - sizeToTruncate, sizeToTruncate));
                //we do this on the second level as well
                foreach (var childItem in item.Items)
                {
                    if (childItem.Caption.Length > sizeToTruncate)
                        childItem.Caption = string.Format("...{0}", childItem.Caption.Substring(childItem.Caption.Length - sizeToTruncate, sizeToTruncate));
                }
            }
        }
    }
}
